package services

import (
	"context"
	"fmt"
	"sync"
	"time"

	"enzyme-backend/core/models"
	"enzyme-backend/core/storage"
	"enzyme-backend/core/utils"

	"github.com/gin-gonic/gin"
)

var (
	// GlobalUser 全局用户服务实例
	GlobalUser *UserService
	userOnce   sync.Once
)

// UserService 用户服务
type UserService struct {
	userStorage     UserStorage
	registerStorage RegisterStorage
	emailStorage    EmailStorage
}

// UserStorage 用户存储接口
type UserStorage interface {
	// 用户相关操作
	LoginForToken(ctx context.Context, fingerprint string, email string, password string) (string, error)
	VerifyToken(ctx context.Context, token string) error

	GetUserByToken(ctx context.Context, user *models.UserModel, token string) error
	GetUserByEmail(ctx context.Context, user *models.UserModel, email string) error
	CreateUser(ctx context.Context, user *models.UserModel) error
	UpdateUser(ctx context.Context, user *models.UserModel) error

	GetDeviceByFingerprint(ctx context.Context, device *models.DeviceModel, fingerprint string) error
	GetDeviceByToken(ctx context.Context, device *models.DeviceModel, token string) error
	CreateDevice(ctx context.Context, device *models.DeviceModel) error
	UpdateDevice(ctx context.Context, device *models.DeviceModel) error
}

// UserStorage 用户存储接口
type RegisterStorage interface {
	// 注册事务相关操作
	CreateRegisterTransaction(ctx context.Context, email string, verifyCode string, expiredAt time.Time) error
	GetRegisterTransaction(ctx context.Context, email string) (*models.RegisterTransaction, error)
	DeleteRegisterTransaction(ctx context.Context, email string) error
}

type EmailStorage interface {
	GetEmailCode(ctx context.Context, email string) (string, error)
	SetEmailCode(ctx context.Context, email, code string) error
	DelEmailCode(ctx context.Context, email string) error
}

// init 初始化用户服务
func init() {
	userOnce.Do(func() {
		// 创建用户服务
		GlobalUser = &UserService{
			userStorage:     storage.GlobalPSQL,
			registerStorage: storage.GlobalRedis,
			emailStorage:    storage.GlobalRedis,
		}
		utils.GlobalLogger.Info("用户服务已初始化")
	})
}

// Login 用户登录
func (us *UserService) Login(c *gin.Context, email, password, fingerprint string) (string, error) {
	// 获取用户
	token, err := us.userStorage.LoginForToken(c, fingerprint, email, password)
	if err != nil {
		return "", fmt.Errorf("用户不存在: %w", err)
	}
	return token, nil
}

// SendVerifyCode 发送验证码
func (us *UserService) SendVerifyCode(c *gin.Context, email string) error {
	// 生成验证码
	verifyCode := utils.GenerateVerifyCode()

	// 保存验证码到Redis
	if err := us.emailStorage.SetEmailCode(c, email, verifyCode); err != nil {
		return fmt.Errorf("保存验证码失败: %w", err)
	}

	// 发送验证码邮件
	if err := GlobalEmail.SendVerifyCode(c, email, verifyCode); err != nil {
		return fmt.Errorf("发送验证码失败: %w", err)
	}

	return nil
}

// Register 用户注册
func (us *UserService) Register(c *gin.Context, email, password, verifyCode, fingerprint string) error {
	// 验证邮箱验证码
	if err := us.verifyEmailCode(c, email, verifyCode); err != nil {
		return fmt.Errorf("验证码错误: %w", err)
	}

	if fingerprint == "" {
		return fmt.Errorf("指纹为空")
	}

	// 检查邮箱是否已被使用
	var user models.UserModel
	if err := us.userStorage.GetUserByEmail(c, &user, email); err == nil {
		return fmt.Errorf("邮箱已被使用")
	}

	// 检查指纹是否已被使用
	var device models.DeviceModel
	if err := us.userStorage.GetDeviceByFingerprint(c, &device, fingerprint); err == nil {
		if device.UserToken != "" {
			return fmt.Errorf("指纹已被使用")
		}
	}

	user = models.UserModel{
		Email:       email,
		Password:    password,
		Token:       utils.GenerateHex(16),
		ExpiredAt:   storage.TheBeginOfTheWorld,
		UsageAmount: 0,
	}
	if err := us.userStorage.CreateUser(c, &user); err != nil {
		return fmt.Errorf("创建用户失败: %w", err)
	}

	// update device
	device.Token = user.Token
	if err := us.userStorage.UpdateDevice(c, &device); err != nil {
		return fmt.Errorf("更新设备失败: %w", err)
	}

	return nil
}

// VerifyToken 验证token
func (us *UserService) VerifyToken(c *gin.Context, token string) error {
	return us.userStorage.VerifyToken(c, token)
}

// GetUserByToken 通过token获取用户
func (us *UserService) GetUserByToken(c *gin.Context, token string) (*models.UserModel, error) {
	var user models.UserModel
	if err := us.userStorage.GetUserByToken(c, &user, token); err != nil {
		return nil, err
	}
	return &user, nil
}

// GetDeviceByToken 通过token获取设备
func (us *UserService) GetDeviceByToken(c *gin.Context, token string) (*models.DeviceModel, error) {
	var device models.DeviceModel
	if err := us.userStorage.GetDeviceByToken(c, &device, token); err != nil {
		return nil, err
	}
	return &device, nil
}

// RemakePassword 重置密码
func (us *UserService) RemakePassword(c *gin.Context, email, verifyCode, newPassword string) error {
	// 验证邮箱验证码
	if err := us.verifyEmailCode(c, email, verifyCode); err != nil {
		return fmt.Errorf("验证码错误: %w", err)
	}

	// 获取用户
	var user models.UserModel
	if err := us.userStorage.GetUserByEmail(c, &user, email); err != nil {
		return fmt.Errorf("用户不存在: %w", err)
	}

	// 更新密码
	user.Password = newPassword
	if err := us.userStorage.UpdateUser(c, &user); err != nil {
		return fmt.Errorf("更新密码失败: %w", err)
	}

	return nil
}

// verifyEmailCode 验证邮箱验证码
func (us *UserService) verifyEmailCode(c *gin.Context, email, verifyCode string) error {
	// 从Redis获取验证码
	savedCode, err := us.emailStorage.GetEmailCode(c, email)
	if err != nil {
		return fmt.Errorf("获取验证码失败: %w", err)
	}

	// 验证码不匹配
	if savedCode != verifyCode {
		return fmt.Errorf("验证码不匹配")
	}

	// 删除已使用的验证码
	if err := us.emailStorage.DelEmailCode(c, email); err != nil {
		utils.GlobalLogger.Error("删除验证码失败: %v", err)
	}

	return nil
}
